<?php


namespace models\Business;


use Exception;
use models\DAO\OrderModel;
use models\Exception\Business\AlibabaproductException;
use models\Exception\Business\BookingException;
use models\Exception\Business\MemberException;
use models\Exception\Business\OrderException;
use models\Exception\Business\TurnoverException;
use models\Exception\DAO\ModelDriverException;
use models\Exception\DAO\ModelException;
use models\Exception\DAO\ModelReflectionException;
use models\Exception\DAO\ModelSqlException;
use models\Exception\Service\ServiceException;
use models\Exception\Transformer\TransformerException;
use models\Service\AlibabaproductService;
use models\Service\MemberService;
use models\Service\OrderService;
use models\Service\SystemService;
use Task\client;
use Yaf\Registry;
use ylAlibaba\core\ylAlibabaException;
use ylAlibaba\functions\product\Product;
use youliPhpLib\Common\StringOperation;

class Order
{
    const STATS_GOODS = [1, 2, 3];//待发货，已发货,确认收货
    const PAY_OR_REFUND_ACTION = ['pay', 'refund'];

    /*
     * 订单列表
     */
    static public function getOrderList($parameters = [])
    {
        try {
            $from_api = isset($parameters['from_api']) && $parameters['from_api'] === true;

            $groups = $g_rules = $rules = $condition = [];
            if (isset($parameters['member_id'])) {
                if (isset($parameters['failure_stats'])) {
                    // 登陆用户获取由他参与的拼团，且拼团失败的，当前商品未确认收货的订单
                    if ($parameters['failure_stats'] == 'toBeContinued') {
                        $parameters['stats'] = 0;
                    } else if ($parameters['failure_stats'] == 'cancel')
                        $parameters['stats'] = 100;

                    array_push($rules, ['field' => 'fail_member_id', 'op' => 'eq', 'data' => $parameters['member_id']]);
                } else
                    array_push($rules, ['field' => 'member_id', 'op' => 'eq', 'data' => $parameters['member_id']]);
            }
            if (isset($parameters['sn']))
                array_push($rules, ['field' => 'sn', 'op' => 'nc', 'data' => $parameters['sn'] . '%']);
            if (isset($parameters['trade_order_sn']))
                array_push($rules, ['field' => 'trade_order_sn', 'op' => 'nc', 'data' => $parameters['trade_order_sn'] . '%']);
            if (isset($parameters['type']))
                array_push($rules, ['field' => 'type', 'op' => 'eq', 'data' => $parameters['type']]);
            if (isset($parameters['product_id']))
                array_push($rules, ['field' => 'product_id', 'op' => 'eq', 'data' => $parameters['product_id']]);
            if (isset($parameters['pay_type']))
                array_push($rules, ['field' => 'pay_type', 'op' => 'eq', 'data' => $parameters['pay_type']]);

            //后台订单列表筛选
            if ($from_api === false) {
                if (isset($parameters['order_stats']) && !isset($parameters['refund_stats'])) {
                    //退款
                    if ($parameters['order_stats'] == 1)
                        array_push($rules, ['field' => 'refund_stats', 'op' => 'in', 'data' => '1,3,5']);
                    //退货
                    if ($parameters['order_stats'] == 2)
                        array_push($rules, ['field' => 'refund_stats', 'op' => 'in', 'data' => '2,4,6,7,8']);
                } else {
                    if (isset($parameters['refund_stats']))
                        array_push($rules, ['field' => 'refund_stats', 'op' => 'eq', 'data' => $parameters['refund_stats']]);
                }
            }

            //待发货，已发货,确认收货
            if (isset($parameters['stats'])) {
                if (in_array($parameters['stats'], self::STATS_GOODS)) {
                    array_push($rules, ['field' => 'stats', 'op' => 'eq', 'data' => $parameters['stats']]);
                    array_push($rules, ['field' => 'refund_stats', 'op' => 'eq', 'data' => 0]);
                    /*if (in_array($parameters['stats'], [1, 2])) {
                        $system = SystemService::getInstance()->getOne(1);
                        array_push($rules, ['field' => 'coupon_at', 'op' => 'ge', 'data' => date('Y-m-d H:i:s', time() - $system['coupon_expire'])]);
                    }*/
                } elseif ($parameters['stats'] == 99) {
                    //为待支付、待发货、待收货的全部订单
                    array_push($rules, ['field' => 'stats', 'op' => 'in', 'data' => '1,2,3']);
                    array_push($rules, ['field' => 'refund_stats', 'op' => 'eq', 'data' => 0]);

                } elseif ($parameters['stats'] == 100) {
                    //为退款与退货全部
                    array_push($rules, ['field' => 'stats', 'op' => 'in', 'data' => '1,2']);
                    array_push($rules, ['field' => 'refund_stats', 'op' => 'gt', 'data' => 0]);
                } elseif ($parameters['stats'] == 101) {
                    //为退货中
                    array_push($rules, ['field' => 'stats', 'op' => 'in', 'data' => '1,2']);
                    array_push($rules, ['field' => 'refund_stats', 'op' => 'in', 'data' => '7,8']);
                } elseif ($parameters['stats'] == 102) {
                    //为处理中
                    array_push($rules, ['field' => 'stats', 'op' => 'in', 'data' => '1,2']);
                    array_push($rules, ['field' => 'refund_stats', 'op' => 'eq', 'data' => 2]);
                } elseif ($parameters['stats'] == 103) {
                    //为已退货
                    array_push($rules, ['field' => 'stats', 'op' => 'in', 'data' => '1,2']);
                    array_push($rules, ['field' => 'refund_stats', 'op' => 'eq', 'data' => 4]);
                } elseif ($parameters['stats'] == 104) {
                    //为退款中
                    array_push($rules, ['field' => 'stats', 'op' => 'in', 'data' => '1,2']);
                    array_push($rules, ['field' => 'refund_stats', 'op' => 'eq', 'data' => 1]);
                } elseif ($parameters['stats'] == 105) {
                    //已退款
                    array_push($rules, ['field' => 'stats', 'op' => 'in', 'data' => '1,2']);
                    array_push($rules, ['field' => 'refund_stats', 'op' => 'eq', 'data' => 3]);
                } elseif ($parameters['stats'] == 106) {
                    //退款失败
                    array_push($rules, ['field' => 'stats', 'op' => 'in', 'data' => '1,2']);
                    array_push($rules, ['field' => 'refund_stats', 'op' => 'eq', 'data' => 5]);
                } elseif ($parameters['stats'] == 107) {
                    //退货失败
                    array_push($rules, ['field' => 'stats', 'op' => 'in', 'data' => '1,2']);
                    array_push($rules, ['field' => 'refund_stats', 'op' => 'in', 'data' => '6,9']);
                }
            }

            if (isset($parameters['start_created_date']))
                array_push($rules, ['field' => 'created_at', 'op' => 'ge', 'data' => date("Y-m-d 00:00:00", strtotime(str_replace('/', '-', $parameters['start_created_date'])))]);
            if (isset($parameters['end_created_date']))
                array_push($rules, ['field' => 'created_at', 'op' => 'le', 'data' => date("Y-m-d 00:00:00", strtotime(str_replace('/', '-', $parameters['end_created_date'])))]);
            if (isset($parameters['start_refunded_date']))
                array_push($rules, ['field' => 'refunded_at', 'op' => 'ge', 'data' => date("Y-m-d 00:00:00", strtotime(str_replace('/', '-', $parameters['start_refunded_date'])))]);
            if (isset($parameters['end_refunded_date']))
                array_push($rules, ['field' => 'refunded_at', 'op' => 'le', 'data' => date("Y-m-d 00:00:00", strtotime(str_replace('/', '-', $parameters['end_refunded_date'])))]);
            if (isset($parameters['start_returned_date']))
                array_push($rules, ['field' => 'returned_at', 'op' => 'ge', 'data' => date("Y-m-d 00:00:00", strtotime(str_replace('/', '-', $parameters['start_returned_date'])))]);
            if (isset($parameters['end_returned_date']))
                array_push($rules, ['field' => 'returned_at', 'op' => 'le', 'data' => date("Y-m-d 00:00:00", strtotime(str_replace('/', '-', $parameters['end_returned_date'])))]);

            if (!empty($rules)) {
                $condition = ['groupOp' => 'AND', 'rules' => $rules, 'groups' => $groups];
            }
            $order_list = OrderService::getInstance()->getList(
                isset($parameters['page']) ? $parameters['page'] : 1,
                isset($parameters['page_size']) ? $parameters['page_size'] : 10,
                isset($parameters['sort']) ? $parameters['sort'] : 'desc',
                isset($parameters['order']) ? $parameters['order'] : 'created_at',
                $condition
            );
            if (isset($parameters['stats']))
                $order_list = self::getOrderStats($order_list, $parameters['stats']);

            if (empty($order_list['data']))
                throw new OrderException(OrderException::ORDER_IS_NOT_EXISTS, OrderException::ORDER_IS_NOT_EXISTS_NO);

            $order_list = AlibabaProduct::getProductByModules($order_list);

            if (!isset($parameters['from_api']) || $parameters['from_api'] === false) {
                $order_list = Address::getAddressByModules($order_list);
            }

            $system = System::getSystemInfo(1);
            foreach ($order_list['data'] as $idx => $order_info) {
                if($order_info['refund_stats']==3){
                    //amount 包含运费
                    //退款成功 所退金额= 商品价格-服务费
                    $refund_amount=$order_info['amount']-$order_info['service_fee'];
                }elseif ($order_info['refund_stats']==4){
                    //退货成功 所退金额= 商品价格-服务费-运费
                    $refund_amount=$order_info['amount']-$order_info['service_fee']-$order_info['fee'];
                }else{
                    $refund_amount=0;
                }
                $order_list['data'][$idx]['refund_amount']=sprintf('%.2f',$refund_amount);
                if (!isset($order_info['expired_at'])) {
                    $order_list['data'][$idx]['expired_at'] = date('Y-m-d H:i:s', strtotime($order_info['created_at']) + $system['coupon_expire']);
                }
            }


            return $order_list;

        } catch (ModelDriverException $e) {
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

    //order订单中文状态
    static public function getOrderStats($order_list, $stats)
    {
        foreach ($order_list['data'] as $k => $v) {
            if ($stats <= 99) {
                switch ($v['stats']) {
                    case '1':
                        $order_list['data'][$k]['statsname'] = '待发货';
                        break;
                    case '2':
                        $order_list['data'][$k]['statsname'] = '待收货';
                        break;
                    case '3':
                        $order_list['data'][$k]['statsname'] = '确认收货';
                        break;
                }
            }
            if ($stats >= 100) {
                switch ($v['refund_stats']) {
                    case '1':
                        $order_list['data'][$k]['statsname'] = '退款中';
                        break;
                    case '2':
                        $order_list['data'][$k]['statsname'] = '待处理';
                        break;
                    case '3':
                        $order_list['data'][$k]['statsname'] = '退款成功';
                        break;
                    case '4':
                        $order_list['data'][$k]['statsname'] = '退货成功';
                        break;
                    case '5':
                        $order_list['data'][$k]['statsname'] = '退款失败';
                        break;
                    case '6':
                        $order_list['data'][$k]['statsname'] = '退货失败';
                        break;
                    case '7':
                        $order_list['data'][$k]['statsname'] = '退货中';
                        break;
                    case '8':
                        $order_list['data'][$k]['statsname'] = '退货中';
                        break;
                }
            }
        }
        return $order_list;
    }

    //order订单详情页中文状态
    static public function getOrderDetailName($stats,$refund_stats)
    {
        if($refund_stats==0){
            switch ($stats) {
                case '1':
                    $statsname = '买家已付款，等待商家发货';
                    break;
                case '2':
                    $statsname = '商家已发货，等待买家收货';
                    break;
                case '3':
                    $statsname = '买家已确认收货';
                    break;
            }
        }else{
            switch ($refund_stats) {
                case '1':
                    $statsname = '等待商家处理退款申请';
                    break;
                case '2':
                    $statsname = '请等待商家处理';
                    break;
                case '3':
                    $statsname = '退款成功';
                    break;
                case '4':
                    $statsname = '退货成功';
                    break;
                case '5':
                    $statsname = '退款失败，商家拒绝您的退款申请';
                    break;
                case '6':
                    $statsname = '退货失败，商家拒绝您的退款申请';
                    break;
                case '7':
                    $statsname = '退货中，等待买家退货';
                    break;
                case '8':
                    $statsname = '退货中，等待商家收货';
                    break;
                case '9':
                    $statsname = '退货失败，商家拒收了您的快递';
                    break;
            }
        }
        return $statsname;
    }
    /**
     * 查询订单
     * @return array|mixed|null
     * @throws OrderException
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws ServiceException
     * @throws TransformerException
     */
    static public function getOrderBySn($sn)
    {
        try {
            return OrderService::getInstance()->getOne($sn);
        } catch (ModelDriverException $e) {
            throw $e;
        } catch (ModelException $e) {
            if ($e->getCode() == ModelException::DATA_NOT_EXISTS_NO)
                throw new OrderException(OrderException::ORDER_IS_NOT_EXISTS, OrderException::ORDER_IS_NOT_EXISTS_NO);
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

    /**
     * 创建订单
     * @param array $parameters
     * @return array
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws OrderException
     * @throws TransformerException
     */
    static public function createOrder($parameters = [])
    {
        try {
            $system = System::getSystemInfo(1);
            $service_rate  = $system['service_rate'] ? $system['service_rate']/100 : 0;
            return OrderService::getInstance()->create(
                $parameters['sn'],
                isset($parameters['fail_sn']) ? $parameters['fail_sn'] : '',
                '',
                $parameters['type'],
                $parameters['product_id'],
                $parameters['sku_id'],
                isset($parameters['activity_id']) && !empty($parameters['activity_id']) ? $parameters['activity_id'] : 0,
                $parameters['member_id'],
                $parameters['fail_member_id'],
                $parameters['address_id'],
                $parameters['pay_type'],
                $parameters['amount'],
                $parameters['fee'],
                1,
                0,
                0,
                0,
                0,
                $service_rate*($parameters['amount']-$parameters['fee']),
                '0000-00-00 00:00:00',
                '0000-00-00 00:00:00',
                '0000-00-00 00:00:00'
            );
        } catch (ModelDriverException $e) {
            Registry::get('order_log')->err("创建order表数据失败: " . $e->getMessage());
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new OrderException(OrderException::ORDER_CREATE_FAILURE, OrderException::ORDER_CREATE_FAILURE_NO);
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

    /**
     * 处理订单
     * @param array $parameters
     * @throws MemberException
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws OrderException
     * @throws TransformerException
     */
    static public function handleOrder($parameters = [])
    {

        $order_model = OrderModel::getInstance();
        $conn        = $order_model->getConn();
        $conn->beginTransaction();
        try {
            // 是否因为利润小于0而给拼团胜出的买家退款
            $profit = 0;
            if ($parameters['alibaba_order']) {
                //1688订单号
                $trade_order_sn = $parameters['alibaba_order']['orderId'];
                //运费
                $post_fee = $parameters['alibaba_order']['postFee'] / 100;
                // 成本
                $cost = $parameters['alibaba_order']['totalSuccessAmount'] / 100;
                // 利润
                $profit = $parameters['amount']  - $cost;
                // 利润小于等于0，日志记录数据
                if ($profit <= 0) {
                    Registry::get('order_log')->info("订单利润小于等于0." . json_encode($parameters));
                }

                // 修改order表的订单状态为1(待发货)
                $sql = "UPDATE `order` SET `stats` = '1',`trade_order_sn` ='" . $trade_order_sn . "',`post_fee` ='" . $post_fee . "', `cost` = '" . $cost . " ' WHERE `sn` = '" . $parameters['sn'] . "'";
                Registry::get('db_log')->info("修改1688订单的sql: " . $sql);
                $conn->executeQuery($sql);
            }
            $system = SystemService::getInstance()->getOne(1);

            if ($parameters['fail_member_id']) {
//                list($update_balance_sql, $insert_turnover_sql) = Member::calCouponFailureMemberIntegral($parameters['fail_member_id'], $parameters['amount'], 0.5);
                //商品成本（不含运费）
                $good_cost = $cost - $post_fee;
                //获取商品名
                $product = AlibabaproductService::getInstance()->getOne($parameters['product_id']);
                $title = isset($product['title'])?$product['title']:'';
                list($update_balance_sql, $insert_turnover_sql) = Member::calCouponFailureMemberIntegral($parameters['fail_member_id'], $parameters['amount']-$parameters['fee'], $good_cost, $parameters['fee'],true,1,$title,$parameters['sn']);
                if (!empty($update_balance_sql))
                    $conn->executeQuery($update_balance_sql);

                if (!empty($insert_turnover_sql))
                    $conn->executeQuery($insert_turnover_sql);

                // 拼团失败新增一条归还余额的流水记录
                /*$sql = "INSERT INTO `turnover` (`type`, `member_id`, `stats`, `remark`, `currency`, `amount`, `remain`) " .
                    "VALUE ('4', '" . $parameters['fail_member_id'] . "', '1', '拼团失败，归还余额', '" . $failmember['balance'] . "', '" . abs($parameters['amount']) . "', '" . ($failmember['balance'] + abs($parameters['amount'])) . "')";
                Registry::get('db_log')->info("拼团失败，归还余额sql: " . $sql);
                $conn->executeQuery($sql);

                // 拼团失败归还余额
                $update_fail_member = "UPDATE `member` SET `coupon_order_number` = `coupon_order_number` +1 , `balance` = `balance` + " . abs($parameters['amount']) . " WHERE `id` = '" . $failmember['id'] . "'";
                Registry::get('db_log')->info("拼团失败,归还member的sql: " . $update_fail_member);
                $conn->executeQuery($update_fail_member);*/

                //推送消息给指定会员
                //消息推送 sendCouponRes已推送
//                $sql = "INSERT INTO `announce` (`type`, `member_id`, `title`, `content`, `is_push`, `created_at`) " .
//                    "VALUE ('1', '" . $parameters['fail_member_id'] . "', '拼单失败','您拼单失败','1','" . date('Y-m-d H:i:s', time()) . "')";
//                Registry::get('db_log')->info("拼单失败，消息推送sql: " . $sql);
//                $conn->executeQuery($sql);

                //修改booking状态为拼团失败
                $update_book_fail = "UPDATE `booking` SET `stats` = '10' WHERE `sn` = '" . $parameters['fail_sn'] . "'";
                Registry::get('db_log')->info("拼单失败，订购信息booking的sql: " . $update_book_fail);
                $conn->executeQuery($update_book_fail);

                // 拼团失败会员 修改拼团次数
                // 注释掉，因为在business/member.php的calCouponFailureMemberIntegral中已经实现
//                $failure_member_coupon_num_sql = "UPDATE `member` SET `coupon_order_number` = `coupon_order_number` + 1 WHERE `id` = " . $parameters['fail_member_id'];
//                Registry::get('db_log')->info("拼团失败会员修改参与拼团次数sql: " . $failure_member_coupon_num_sql);
//                $conn->executeQuery($failure_member_coupon_num_sql);
            }

            // 拼团成功添加拼团成功金额
            if ($parameters['member_id']) {
                $member = MemberService::getInstance()->getOne($parameters['member_id']);
                if (empty($member))
                    throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);

                $update_member = "UPDATE `member` SET `coupon_order_number` = `coupon_order_number` +1, " .
                    "`coupon_success_order_num` = `coupon_success_order_num` + 1, `coupon_amount` = `coupon_amount` + " .
                    abs($parameters['amount']) . ", `coupon_profit` = `coupon_profit` + '" . $profit . "' WHERE `id` = '" . $member['id'] . "'";
                Registry::get('db_log')->info("拼单成功，增加member的sql: " . $update_member);
                $conn->executeQuery($update_member);


                //消息推送 sendCouponRes已推送
//                $sql = "INSERT INTO `announce` (`type`, `member_id`, `title`, `content`, `is_push`, `created_at`) " .
//                    "VALUE ('1', '" . $parameters['member_id'] . "', '拼单成功','您拼单成功','1','" . date('Y-m-d H:i:s', time()) . "')";
//                Registry::get('db_log')->info("拼单成功，消息推送sql: " . $sql);
//                $conn->executeQuery($sql);

                //修改booking状态为拼团成功
                $update_book_success = "UPDATE `booking` SET `stats` = '9' WHERE `sn` = '" . $parameters['sn'] . "'";
                Registry::get('db_log')->info("拼单成功，订购信息booking的sql: " . $update_book_success);
                $conn->executeQuery($update_book_success);

                //新用户拼单首次买到商品平台返现

                if($system['userback']>0){
                    $result= Order::newUser($parameters['member_id'],1);
                    if($result){
                        // 新人首次拼单商品补贴
                        $btsql = "INSERT INTO `turnover` (`type`, `member_id`, `stats`, `remark`, `currency`, `amount`, `remain`) " .
                            "VALUE ('4', '" . $parameters['member_id'] . "', '1', '新人首次拼单商品补贴', '" . $member['balance'] . "', '" . abs($system['userback']) . "', '" . ($member['balance'] + abs($system['userback'])) . "')";
                        Registry::get('db_log')->info("新人首次拼单商品补贴sql: " . $btsql);
                        $conn->executeQuery($btsql);

                        // 新人首次拼单商品补贴归还余额
                        $update_bt_member = "UPDATE `member` SET  `balance` = `balance` + " . abs($system['userback']) . " WHERE `id` = '" . $member['id'] . "'";
                        Registry::get('db_log')->info("首次拼单商品补贴member的sql: " . $update_bt_member);
                        $conn->executeQuery($update_bt_member);
                        //消息推送
                        $msg='新人首次拼单商品补贴'.$system['userback'].'元已经转入您的余额';
                        $sql = "INSERT INTO `announce` (`type`, `member_id`, `title`, `content`, `is_push`, `created_at`) " .
                            "VALUE ('1', '" . $parameters['member_id'] . "', '新人拼单补贴','".$msg."','1','" . date('Y-m-d H:i:s', time()) . "')";
                        Registry::get('db_log')->info("新人拼单补贴，消息推送sql: " . $sql);
                        $conn->executeQuery($sql);
                    }
                }
            }

            $conn->commit();
        } catch (ModelDriverException $e) {
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new OrderException(OrderException::ORDER_EDIT_FAILURE, OrderException::ORDER_EDIT_FAILURE_NO);
            throw $e;
        } catch (OrderException $e) {
            throw $e;
        } catch (MemberException $e) {
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        } catch (\Exception $e) {
            $conn->rollback();
            throw new OrderException(OrderException::ORDER_EDIT_FAILURE, OrderException::ORDER_EDIT_FAILURE_NO);
        }
    }

    /**
     * 金豆兑换创建订单
     * @param array $parameters
     * @throws MemberException
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws OrderException
     * @throws TransformerException
     */
    static public function createOrderByIntegral($parameters = [])
    {

        $order_model = OrderModel::getInstance();
        $conn        = $order_model->getConn();
        $conn->beginTransaction();
        try {
            $member_id = $parameters['member_id'];
//            $sn        = StringOperation::genOrderSn();
            $sn = $parameters['sn'];
            //获取用户信息
            $member = MemberService::getInstance()->getOne($member_id);
            if (empty($member))
                throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);
            //总积分
            if ($member['integral'] - $parameters['integral'] < 0) {
                throw new MemberException(MemberException::INTEGRSL_FAILURE, MemberException::INTEGRSL_FAILURE_NO);
            }
            // 调用1688下单接口
            // 调用1688协议支付接口
            $aliOrder      = [
                'sku_id'     => $parameters['sku_id'],
                'address_id' => $parameters['address_id'],
                'product_id' => $parameters['product_id'],
                'num'        => $parameters['num'],
                'member_id'  => $member_id,
                'sn'         => $sn,
                'amount'     => $parameters['amount'],
            ];
            $alibaba_order = self::aliCreateOrder($aliOrder);

            //1688订单号
            $trade_order_sn = $alibaba_order['orderId'];
            //运费
            $post_fee = $alibaba_order['postFee'] / 100;
            // 成本
            $cost = $alibaba_order['totalSuccessAmount'] / 100;
            //获取活动id
            $activity = AlibabaActivity::getActivityByPid($parameters['product_id']);
            if ($activity) {
                $activity_id = $activity['activity_id'];
            }
            $activity_id = isset($activity_id) ? $activity_id : '0';

            $sql = "INSERT INTO `order` (`sn`,`fail_sn`,`trade_order_sn`,`type`,`product_id`,`sku_id`,`activity_id`,`member_id`,`address_id`,`amount`,`stats`,`post_fee`,`cost`, `created_at`,`notified_at`,`refunded_at`,`returned_at`)" .
                " VALUES ('" . $sn . "', '0', '" . $trade_order_sn . "','1','" . $parameters['product_id'] . "','" . $parameters['sku_id'] . "','" . $activity_id . "','" . $member_id . "','" . $parameters['address_id'] . "','" .
                $parameters['integral'] . "','1','" . $post_fee . "','" . $cost . "', '" . date('Y-m-d H:i:s', time()) . "','0000-00-00 00:00:00','0000-00-00 00:00:00','0000-00-00 00:00:00')";
            Registry::get('db_log')->info("金豆兑换新建1688订单的sql: " . $sql);
            $conn->executeQuery($sql);


            // 新增金币消费流水记录
            $sql = "INSERT INTO `turnover` (`type`, `member_id`, `stats`, `remark`, `currency`, `amount`, `remain`) " .
                "VALUE ('1', '" . $member_id . "', '1', '金豆兑换消费', '" . $member['integral'] . "', '" . -abs($parameters['integral']) . "', '" . ($member['integral'] - abs($parameters['integral'])) . "')";
            Registry::get('db_log')->info("金豆兑换消费sql: " . $sql);
            $conn->executeQuery($sql);

            //扣除用户金豆
            $update_fail_member = "UPDATE `member` SET  `integral` = `integral` - " . abs($parameters['integral']) . " WHERE `id` = '" . $member['id'] . "'";
            Registry::get('db_log')->info("兑换商品,扣除金豆member的sql: " . $sql);
            $conn->executeQuery($update_fail_member);

            $conn->commit();
        } catch (ModelDriverException $e) {
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new OrderException(OrderException::ORDER_CREATE_FAILURE, OrderException::ORDER_CREATE_FAILURE_NO);
            throw $e;
        } catch (OrderException $e) {
            throw $e;
        } catch (MemberException $e) {
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        } catch (\Exception $e) {
            $conn->rollback();
            throw new OrderException(OrderException::ORDER_CREATE_FAILURE, OrderException::ORDER_CREATE_FAILURE_NO);
        }
    }

    /**
     * 余额购买创建订单
     * @param array $parameters
     * @throws MemberException
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws OrderException
     * @throws TransformerException
     */
    static public function createOrderByBalance($parameters = [])
    {

        $order_model = OrderModel::getInstance();
        $conn        = $order_model->getConn();
        $conn->beginTransaction();
        try {
            $member_id = $parameters['member_id'];
//            $sn        = StringOperation::genOrderSn();
            $sn     = $parameters['sn'];
            $amount = isset($parameters['amount']) ? $parameters['amount'] : (isset($parameters['price']) ? $parameters['price'] : 0);
            if (empty($amount))
                throw new OrderException(OrderException::INVALID_ORDER_AMOUNT, OrderException::INVALID_ORDER_AMOUNT_NO);
            //获取用户信息
            $member = MemberService::getInstance()->getOne($member_id);
            if (empty($member))
                throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);
            //总余额
            if ($member['balance'] - $amount < 0) {
                throw new MemberException(TurnoverException::BALANCE_NOT_ENOUGH, TurnoverException::BALANCE_NOT_ENOUGH_NO);
            }
            // 调用1688下单接口
            // 调用1688协议支付接口
            /*$aliOrder      = [
                'sku_id'     => $parameters['sku_id'],
                'address_id' => $parameters['address_id'],
                'product_id' => $parameters['product_id'],
                'num'        => $parameters['num'],
                'member_id'  => $member_id,
                'sn'         => $sn,
                'amount'     => $parameters['amount'],
            ];
            $alibaba_order = self::aliCreateOrder($aliOrder);

            //1688订单号
            $trade_order_sn = $alibaba_order['orderId'];
            //运费
            $post_fee = $alibaba_order['postFee'] / 100;
            // 成本
            $cost = $alibaba_order['totalSuccessAmount'] / 100;
            //获取活动id
            $activity = AlibabaActivity::getActivityByPid($parameters['product_id']);
            if ($activity) {
                $activity_id = $activity['activity_id'];
            }
            $activity_id = isset($activity_id) ? $activity_id : '';

            $sql = "INSERT INTO `order` (`sn`,`fail_sn`,`trade_order_sn`,`type`,`pay_type`,`product_id`,`sku_id`,`activity_id`,`member_id`,`address_id`,`amount`,`stats`,`post_fee`,`cost`, `created_at`,`notified_at`,`refunded_at`,`returned_at`)" .
                " VALUES ('" . $sn . "', '0', '" . $trade_order_sn . "','0','2','" . $parameters['product_id'] . "','" . $parameters['sku_id'] . "','" . $activity_id . "','" . $member_id . "','" . $parameters['address_id'] . "','" .
                $amount . "','1','" . $post_fee . "','" . $cost . "', '" . date('Y-m-d H:i:s', time()) . "','0000-00-00 00:00:00','0000-00-00 00:00:00','0000-00-00 00:00:00')";
            Registry::get('db_log')->info("余额购买新建1688订单的sql: " . $sql);
            $conn->executeQuery($sql);*/

            // 新增金币消费流水记录
            $product = AlibabaproductService::getInstance()->getOne($parameters['product_id']);
            $title = isset($product['title'])?$product['title']:'';
            $remark ='您在“'.$title.'”使用余额进行支付拼单。订单号：'.$parameters['sn'];
            $sql = "INSERT INTO `turnover` (`type`, `member_id`, `stats`, `remark`, `currency`, `amount`, `remain`) " .
                "VALUE ('7', '" . $member_id . "', '1', '".$remark."', '" . $member['balance'] . "', '" . -abs($amount) . "', '" . ($member['balance'] - abs($amount)) . "')";
            Registry::get('db_log')->info("余额购买消费sql: " . $sql);
            $conn->executeQuery($sql);

            //扣除用户余额
            $update_fail_member = "UPDATE `member` SET  `balance` = `balance` - " . abs($amount) . " WHERE `id` = '" . $member['id'] . "'";
            Registry::get('db_log')->info("购买商品,扣除余额member的sql: " . $sql);
            $conn->executeQuery($update_fail_member);

            $conn->commit();

            // 余额支付成功
            // 查询订单是否存在 + 修改booking订单状态 + 将booking从wait4pay队列中删除 + 将booking数据添加到paid队列
            Booking::handlerNotifyByBookingSn($parameters['sn'], 'balancePayout' . time(), 1);

        } catch (ModelDriverException $e) {
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new OrderException(OrderException::ORDER_CREATE_FAILURE, OrderException::ORDER_CREATE_FAILURE_NO);
            throw $e;
        } catch (OrderException $e) {
            throw $e;
        } catch (MemberException $e) {
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        } catch (\Exception $e) {
            $conn->rollback();
            throw new OrderException(OrderException::ORDER_CREATE_FAILURE, OrderException::ORDER_CREATE_FAILURE_NO);
        }
    }

    /**
     * 编辑订单表数据
     * @param array $parameters
     * @return array|mixed|null
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws OrderException
     * @throws ServiceException
     * @throws TransformerException
     */
    static public function editOrder($parameters = [])
    {
        try {
            if (!isset($parameters['sn']) || empty($parameters['sn']))
                throw new OrderException(OrderException::ORDER_ID_IS_EMPTY, OrderException::ORDER_ID_IS_EMPTY_NO);

            $update_arr = [];
            if (isset($parameters['stats']))
                $update_arr['stats'] = $parameters['stats'];
            if (isset($parameters['trade_order_sn']))
                $update_arr['trade_order_sn'] = $parameters['trade_order_sn'];
            if (isset($parameters['refund_stats']))
                $update_arr['refund_stats'] = $parameters['refund_stats'];
            if (isset($parameters['refunded_at']))
                $update_arr['refunded_at'] = $parameters['refunded_at'];
            if (isset($parameters['returned_at']))
                $update_arr['returned_at'] = $parameters['returned_at'];
            if (!empty($update_arr)) {
                $update_arr['updated_at'] = date('Y-m-d H:i:s', time());

                $order = OrderService::getInstance()->update($update_arr, $parameters['sn']);
            } else
                $order = OrderService::getInstance()->getOne($parameters['sn']);

            return $order;
        } catch (OrderException $e) {
            throw $e;
        } catch (ModelDriverException $e) {
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new OrderException(OrderException::ORDER_EDIT_FAILURE, OrderException::ORDER_EDIT_FAILURE_NO);
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

    /**
     *根据1688订单号获取信息
     */
    static public function getOrderByTradeSn($trade_order_sn)
    {
        try {
            return OrderService::getInstance()->getOne(['groupOp' => 'AND', 'rules' => [
                ['field' => 'trade_order_sn', 'op' => 'eq', 'data' => $trade_order_sn],
            ]]);
        } catch (ModelDriverException $e) {
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new OrderException(OrderException::ORDER_IS_NOT_EXISTS, OrderException::ORDER_IS_NOT_EXISTS_NO);
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

    //拼团判断获胜者
    static public function winMember($booking = [])
    {
        if (count($booking) == 1) {
            //添加机器人
            //获取system机器人胜率
            $system = SystemService::getInstance()->getOne(1);
            $rate   = $system['coupon_bot_rate'] ? $system['coupon_bot_rate'] : 30;
        } else {
            // 购买商品数量多的用户，就一定获胜
            $num_arr = array_column($booking, 'member_id', 'num');
            if (count($num_arr) > 1) {
                krsort($num_arr);
                return array_search(array_values($num_arr)[0], array_column($booking, 'member_id'));
            }

            $rate = 50;
        }
        // 判断到底谁在拼团中获胜
        $rand = mt_rand(1, 100);

        if ($rand <= $rate) {
            $k = 1;//第二人 赢（可能为机器人）
        } else {
            $k = 0;//第一人赢
        }
        return $k;
    }


    /* 转化order数据
     * @jqmem 1为机器人 0非机器人
     * @$k 0第一人赢 1第二人 赢（可能为机器人）
     */
    static public function orderData($data = [], $jqmem = 0, $k = 0)
    {
        $order_data = [];
        //不为机器人
        if (!$jqmem || !$k) {
            $activity = AlibabaActivity::getActivityByPid($data[$k]['product_id']);
            if ($activity) {
                $activity_id = $activity['activity_id'];
            }

            $aliOrder['product_id'] = $data[$k]['product_id'];
            $aliOrder['num']        = $data[$k]['num'];
            $aliOrder['sku_id']     = $data[$k]['sku_id'];
            $aliOrder['member_id']  = $data[$k]['member_id'];
            $aliOrder['address_id'] = $data[$k]['address_id'];

            //校验数量和sku_id
            $num_arr = explode(',', $aliOrder['num']);
            if ($aliOrder['sku_id']) {
                $sku_id_arr = explode(',', $aliOrder['sku_id']);
            }
            if (count($num_arr) > 1 && count($num_arr) != count($sku_id_arr)) {
                throw new AlibabaproductException(AlibabaproductException::ALIBABAPRODUCT_NUM_PRODUCT_NOT_EXISTS, AlibabaproductException::ALIBABAPRODUCT_NUM_PRODUCT_NOT_EXISTS_NO);
            }
            // 调用1688接口，校验商品库存
            foreach ($num_arr as $key => $value) {
                $sku_id = $sku_id_arr ? $sku_id_arr[$key] : '';
                if ($key == 0) {
                    $coupon = new Coupon($aliOrder['product_id'], $value, $aliOrder['member_id'], $sku_id);
                }
                $coupon->setNum($value);
                $coupon->setSkuId($sku_id);
                // 调用1688接口，校验商品库存
                $ali_store = $coupon->checkStoreFromAlibaba();
                if ($ali_store !== true)
                    throw new AlibabaproductException(AlibabaproductException::ALIBABAPRODUCT_INVALID_STORE, AlibabaproductException::ALIBABAPRODUCT_INVALID_STORE_NO);
                //总数量
                //$order_data['nums'] += $value;
                //获取指定商品信息
                $coupon->getProductInfoFromLocal();
                $productLocal = $coupon->getProductFromLocal();
                //总价
                $aliOrder['amounts'] += $productLocal['amount'] * $value;
                //单价
                if ($sku_id)
                    $order_data['amountarr'][$sku_id] = $productLocal['amount'];
                else
                    $order_data['amountarr'] = $productLocal['amount'];
            }

        }
        $activity_id = isset($activity_id) ? $activity_id : 0;

        $order_data['member_id']      = ($jqmem && $k) ? 0 : $data[$k]['member_id'];
        $order_data['fail_member_id'] = ($jqmem && $k) ? $data[0]['member_id'] : $data[abs($k - 1)]['member_id'];
        $order_data['sn']             = ($jqmem && $k) ? StringOperation::genOrderSn() : $data[$k]['sn'];
        $order_data['fail_sn']        = ($jqmem && $k) ? $data[0]['sn'] : $data[abs($k - 1)]['sn'];
        $order_data['type']           = 0;
        $order_data['product_id']     = ($jqmem && $k) ? $data[0]['product_id'] : $data[$k]['product_id'];
        $order_data['sku_id']         = ($jqmem && $k) ? $data[0]['sku_id'] : $data[$k]['sku_id'];
        $order_data['activity_id']    = ($jqmem && $k) ? $activity_id : $activity_id;
        $order_data['address_id']     = ($jqmem && $k) ? $data[0]['address_id'] : $data[$k]['address_id'];
        $order_data['pay_type']       = ($jqmem && $k) ? $data[0]['channel'] : $data[$k]['channel'];
        $order_data['amount']         = ($jqmem && $k) ? $data[0]['price'] : $data[$k]['price'];
        $order_data['num']            = ($jqmem && $k) ? $data[0]['num']: $data[$k]['num'];
        $order_data['fee']            = ($jqmem && $k) ? $data[0]['fee']: $data[$k]['fee'];
        return $order_data;
    }

    //根据商品信息获取兑换积分值
    static public function productIntegral($productLocal = [])
    {
        if (!isset($productLocal['integral']) || $productLocal['integral'] == 0) {
            //获取system兑换商品所需的积分与商品价格的比例
            $system   = SystemService::getInstance()->getOne(1);
            $rate     = $system['exchange_rate'] ? $system['exchange_rate'] / 100 : 10;
            $integral = $productLocal['amount'] * $rate;
        } else {
            $integral = $productLocal['integral'];
        }
        return $integral;
    }

    /**
     * 确认收货
     * @param $order_sn
     * @return array|mixed|null
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws OrderException
     * @throws ServiceException
     * @throws TransformerException
     */
    static public function confirmOrder($order_sn)
    {
        $order = self::getOrderBySn($order_sn);
        if (empty($order) || empty($order['trade_order_sn']))
            throw new OrderException(OrderException::ORDER_IS_NOT_EXISTS, OrderException::ORDER_IS_NOT_EXISTS_NO);
        // 判断订单是否隶属于当前操作者
        if ($order['member_id'] != Registry::get('jwt_info')->id)
            throw new OrderException(OrderException::ORDER_DENIED, OrderException::ORDER_DENIED_NO);
        // 判断订单状态是否为"已发货"
        if ($order['stats'] != 2)
            throw new OrderException(OrderException::ORDER_CONFIRM, OrderException::ORDER_CONFIRM_NO);

        //获取商品标题
        $product =  AlibabaproductService::getInstance()->getOne($order['product_id']);
        if (empty($product))
            throw new AlibabaproductException(AlibabaproductException::ALIBABAPRODUCT_IS_NOT_EXISTS, AlibabaproductException::ALIBABAPRODUCT_IS_NOT_EXISTS_NO);
        $order_model = OrderModel::getInstance();
        $conn        = $order_model->getConn();
        $conn->beginTransaction();

        try {
            // 修改booking
            $update_booking_sql = "UPDATE `booking` SET `stats` = 6 WHERE `sn` = '" . $order['sn'] . "'";
            Registry::get('db_log')->info("修改booing状态sql: " . $update_booking_sql);
            $conn->executeQuery($update_booking_sql);

            // 修改order
            $update_order_sql = "UPDATE `order` SET `stats` = 3 WHERE `sn` = '" . $order['sn'] . "'";
            Registry::get('db_log')->info("修改订单状态sql: " . $update_order_sql);
            $conn->executeQuery($update_order_sql);

            $update_balance_sql = $insert_turnover_sql = '';
            // 给拼团失败的用户及其上级、上上级分发金豆
            if (!empty($order['fail_member_id']))
//                list($update_balance_sql, $insert_turnover_sql) = Member::calCouponFailureMemberIntegral(
//                    $order['fail_member_id'], $order['amount'], 0.5, false);
                list($update_balance_sql, $insert_turnover_sql) = Member::calCouponFailureMemberIntegral(
                    $order['fail_member_id'], $order['amount']-$order['fee'], $order['cost'] - $order['post_fee'], $order['fee'],false, 2,$product['title'],$order_sn);

            if (!empty($update_balance_sql))
                $conn->executeQuery($update_balance_sql);

            if (!empty($insert_turnover_sql))
                $conn->executeQuery($insert_turnover_sql);

            // 统计拼团成功用户给平台带来的利润
            $income = $order['amount']  - $order['cost'];
            $sql    = "UPDATE `member` SET `coupon_platform_income` = `coupon_platform_income` + " . abs($income) . " WHERE `id` = '" . $order['member_id'] . "'";
            $conn->executeQuery($sql);

            $conn->commit();

            return $order;
        } catch (\Exception $e) {
            $conn->rollBack();
            Registry::get('db_log')->info(__METHOD__ . ' 用户确认收货sql报错: {' . $e->getMessage() . '}');
            throw new OrderException(OrderException::ORDER_CONFIRM_FALIURE, OrderException::ORDER_CONFIRM_FALIURE_NO);
        }
        // 修改booking的stats为"确认收货"
//        Booking::editBooking(['sn' => $order_sn, 'stats' => 6]);
        // 获取拼团失败的会员信息
//        return Order::editOrder(['sn' => $order_sn, 'stats' => 3]);
    }

    /**
     * 订单退款原因
     */
    static public function refundOrder($order_sn)
    {
        $order = self::getOrderBySn($order_sn);
        // 判断订单是否隶属于当前操作者
        if ($order['member_id'] != Registry::get('jwt_info')->id)
            throw new OrderException(OrderException::ORDER_DENIED, OrderException::ORDER_DENIED_NO);
        if (empty($order) || empty($order['trade_order_sn'])) {
            throw new OrderException(OrderException::ORDER_IS_NOT_EXISTS, OrderException::ORDER_IS_NOT_EXISTS_NO);
        }
        // 判断订单状态是否为"待发货"
        if ($order['stats'] != 1) {
            throw new OrderException(OrderException::ORDER_STATS_WAIT, OrderException::ORDER_STATS_WAIT_NO);
        }
        // 修改booking的stats为"申请退款"
//        Booking::editBooking(['sn' => $order_sn, 'stats' => 4]);
        //查询1688的"查询退款退货原因"接口 alibaba.trade.getRefundReasonList
        $refund_reasons_list = Alibaba::getTradeRefundReasonList($order['trade_order_sn'], 1);
        //退款去除需要上传凭证
        foreach ($refund_reasons_list as $key => $value) {
            if ($value['needVoucher']) {
                unset($refund_reasons_list[$key]);
            }
        }
        rsort($refund_reasons_list);
        return $refund_reasons_list;
    }

    /**
     * 订单退货原因
     */
    static public function returnOrder($order_sn)
    {
        $order = self::getOrderBySn($order_sn);
        if (empty($order) || empty($order['trade_order_sn'])) {
            throw new OrderException(OrderException::ORDER_IS_NOT_EXISTS, OrderException::ORDER_IS_NOT_EXISTS_NO);
        }
        // 判断订单是否隶属于当前操作者
        if ($order['member_id'] != Registry::get('jwt_info')->id)
            throw new OrderException(OrderException::ORDER_DENIED, OrderException::ORDER_DENIED_NO);
        if ($order['stats'] != 2) {
            throw new OrderException(OrderException::ORDER_STATS_ALREADY, OrderException::ORDER_STATS_ALREADY_NO);
        }
        list($delivery_no, $delivery_no_1688, $company_name, $status) = Alibaba::getDeliveryNo($order['trade_order_sn']);

        // 已签收，可能在菜鸟驿站，也可能在蜂巢，也可能是用户签收了 签收后才能退货
        if ($status != 'SIGN') {
            throw new OrderException(OrderException::ORDER_STATS_WAIT_GOODS, OrderException::ORDER_STATS_WAIT_GOODS_NO);
        }
        // 修改booking的stats为"申请退货"
//        Booking::editBooking(['sn' => $order_sn, 'stats' => 5]);
        //查询1688的"查询退款退货原因"接口 alibaba.trade.getRefundReasonList
        $refund_reasons_list = Alibaba::getTradeRefundReasonList($order['trade_order_sn'], 2);
        return $refund_reasons_list;

    }

    /**
     * 提交某个订单的退款理由，并下单
     */
    static public function refundReturn($parameters, $order)
    {
        // 订单金额 单位分
        $amount = ($order['cost'] - $order['post_fee']) * 100;
        // 运费 单位分
        $carriage = $order['post_fee'] * 100;
        // 退款原因编号
        $reason_id = $parameters['reason_id'];
        // 退货、退款原因
        $description = $parameters['reason'];
        // 退货凭证
        if ($parameters['album']) {
            $vouchers = explode(',', $parameters['album']);
            // 上传凭证
            $vouchers_arr = Alibaba::tradeUploadRefundVoucher($parameters['order_sn'], $vouchers);
        } else {
            $vouchers_arr = [];
        }
        $res = Alibaba::getTradeCreateRefund($order['trade_order_sn'], $parameters['order_sn'], $amount, $carriage, $reason_id, $description, $parameters['type'], $vouchers_arr);
        // 退款、退货订单号，需要保存到数据库中
        $refund_order_id = $res['result']['refundId'];
        // 若parameters中存在id则直接使用id作为主键，反之使用refundId作为主键
        $infodata = ['id' => isset($parameters['id']) ? $parameters['id'] : $parameters['refundId'], 'refund_order_id' => $refund_order_id];
        RefundInfo::editInfo($infodata);
        // 因为修改了1688退款退货流程，故此处注释727、730、731、736、737行代码。详情参见application/modules/Api/controllers/Order.php的322行
//        $updatearr['sn'] = $parameters['order_sn'];
        if ($parameters['type'] == 1) {
            // 1、退款+接口调用成功，refund_stats为1(发起退款)，提示客户端"退款申请成功，请等待交易金额退回余额"
//            $updatearr['refund_stats'] = 1;
//            Order::editOrder($updatearr);
            return '退款申请成功，请等待交易金额退回余额';

        } else {
            // 5、退货+"退货接口"接口调用成功+"上传退货凭证"接口调用成功，refund_stats为2(发起退货)，提示客户端"等待卖家处理退货申请"
//            $updatearr['refund_stats'] = 2;
//            Order::editOrder($updatearr);
            return '等待卖家处理退货申请';
        }
    }

    /**
     * 1688下单
     */
    static public function aliCreateOrder($parameters = [])
    {
        try {
            // 商品sku的spec_id，alibabasku中的spec_id字段
            if ($parameters['sku_id']) {
                $sku_arr     = explode(',', $parameters['sku_id']);
                $skuInfo     = AlibabaSku::getSkuByModule($sku_arr);
                $spec_id_arr = array_column($skuInfo['data'], 'spec_id', 'sku_id');
            }

            $num_arr = explode(',', $parameters['num']);
            foreach ($num_arr as $key => $value) {
                $cargoParamList[] = [
                    'offerId'  => $parameters['product_id'],
                    'quantity' => $value,
                    //'sku_id' => $sku_arr[$key],
                ];
                $offers[]         = [
                    'id'    => $parameters['product_id'],
                    'num'   => $value,
                    'price' => isset($sku_arr) ? $parameters['amount'][$sku_arr[$key]] * 100 : $parameters['amount'] * 100,
                ];
                if (isset($spec_id_arr)) {
                    $cargoParamList[$key]['specId'] = $spec_id_arr[$sku_arr[$key]];
                    $offers[$key]['specId']         = $spec_id_arr[$sku_arr[$key]];
                }

            }
            // 获取收货地址信息
            $address_list = Alibaba::getTradeAddressCodeParse($parameters['address_id']);
            // 溢价模式预览订单
            $orderPreview = Alibaba::getCreateOrderPreview4CybMedia($address_list, $cargoParamList);
            //利润=商品总价-成本价（不包含运费）
            if ($parameters['amounts'] && isset($orderPreview['orderPreviewResuslt'][0]['sumPaymentNoCarriage'])) {
                //利润小于0原价退回
                if ($parameters['amounts'] - $orderPreview['orderPreviewResuslt'][0]['sumPaymentNoCarriage'] / 100 <= 0) {
                    Registry::get('order_log')->info("向1688下单，利润<=0，商品价: " . $parameters['amounts'].'原价：'.$orderPreview['orderPreviewResuslt'][0]['sumPaymentNoCarriage']);
                    throw new OrderException(OrderException::ORDER_STATS_FAIL, OrderException::ORDER_STATS_FAIL_NO);
                }
            }
            //获取用户信息
            $memberInfo = Member::getMemberInfoById($parameters['member_id']);

            $order_info = [
                'mediaOrderId' => $parameters['sn'],
                'phone'        => $memberInfo['mobile'],
                'offers'       => $offers,
                //            'offers'       => [
                //                'id'     => $parameters['product_id'],
                //                'specId' => $spec_id,
                //                'price'  => $parameters['price'],
                //                'num'    => $parameters['num']
                //            ],
            ];
            // 溢价模式创建订单
            $result           = Alibaba::getTradeCreateCybMedia($address_list, $cargoParamList, $order_info);
            $alibaba_order_id = $result['orderId'];
            //协议支付单生产者
            // 数据结构
            // {
            //      "trade_order_sn": "阿里巴巴订单编号",
            //      "expired": "订单调用1688溢价模式下单接口的时间+写在system表中的delay时长"
            // }
            $redis = Registry::get('redis');
            try {
                $redis->ping();
            } catch (\Exception $e) {
                $redis->auth(Registry::get('config')['redis']['master']['auth']);
            }
            $redis->select(9);
            $system   = SystemService::getInstance()->getOne(1);
            $platform="alibaba";
            $coupon_delay     = $system['coupon_delay'] ? $system['coupon_delay']  : 0;
            $len = $redis->rpush($platform.'_delay_2_pay', json_encode([
                'trade_order_sn' => $alibaba_order_id,
                'expired' => time()+$coupon_delay
            ]));
            Registry::get('order_log')->info("1688待支付订单号" . $alibaba_order_id."数据长度".$len);
            $client = new client();
            try {
                $client->connect();
                $client->delay2PayOrRefund($alibaba_order_id, $platform, $action = 'pay',$coupon_delay);
            } catch (Exception $e) {

            } finally {
                $client->close();
            }

            //Alibaba::tradePayProtocolPay($alibaba_order_id);
            return $result;
        } catch (ylAlibabaException $e) {
            self::balanceRefund($parameters['sn']);
            Registry::get('alibaba_log')->err("阿里巴巴接口报错: " . $e->getMessage());
        } catch (\Exception $e) {
            Registry::get('alibaba_log')->err("阿里巴巴接口报错!!: " . $e->getMessage());
        }
    }

    /**
     * 1688退款处理
     * @param int $type 退款类型 1退款 2退货
     * @param array $parameters
     * @throws MemberException
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws OrderException
     * @throws TransformerException
     */
    static public function handleRefund($type, $parameters = [])
    {

        $order_model = OrderModel::getInstance();
        $conn        = $order_model->getConn();
        $conn->beginTransaction();
        try {
            if ($parameters['member_id']) {
                $member = MemberService::getInstance()->getOne($parameters['member_id']);
                if (empty($member))
                    throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);

                // 1688退款成功新增一条归还余额的流水记录
                //获取商品名
                $product = AlibabaproductService::getInstance()->getOne($parameters['product_id']);
                $title = isset($product['title'])?$product['title']:'';
                $remark = '您申请的“'.$title.'”退款成功，归还余额。订单号：'.$parameters['sn'];
                $sql = "INSERT INTO `turnover` (`type`, `member_id`, `stats`, `remark`, `currency`, `amount`, `remain`) " .
                    "VALUE ('4', '" . $parameters['member_id'] . "', '1', '".$remark."', '" . $member['balance'] . "', '" . abs($parameters['amount']) . "', '" . ($member['balance'] + abs($parameters['amount'])) . "')";
                Registry::get('db_log')->info("退款成功，归还余额sql: " . $sql);
                $conn->executeQuery($sql);

                // 退款成功归还余额
                if ($type == 1) {
                    $update_member = "UPDATE `member` SET `refund_order_number` = `refund_order_number` +1 , `balance` = `balance` + " . abs($parameters['amount']) . " WHERE `id` = '" . $member['id'] . "'";
                    Registry::get('db_log')->info("退款成功,归还member的sql: " . $update_member);
                } else {
                    $update_member = "UPDATE `member` SET `return_order_number` = `return_order_number` +1 , `balance` = `balance` + " . abs($parameters['amount']) . " WHERE `id` = '" . $member['id'] . "'";
                    Registry::get('db_log')->info("退货成功,归还member的sql: " . $update_member);
                }

                $conn->executeQuery($update_member);
            }
            $conn->commit();
        } catch (ModelDriverException $e) {
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new OrderException(OrderException::ORDER_EDIT_FAILURE, OrderException::ORDER_EDIT_FAILURE_NO);
            throw $e;
        } catch (OrderException $e) {
            throw $e;
        } catch (MemberException $e) {
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        } catch (\Exception $e) {
            $conn->rollback();
            throw new OrderException(OrderException::ORDER_EDIT_FAILURE, OrderException::ORDER_EDIT_FAILURE_NO);
        }
    }

    /**1688下单失败回退金额
     * @param $order_sn
     */
    static public function balanceRefund($order_sn)
    {
        $order = self::getOrderBySn($order_sn);
        if (empty($order)) {
            throw new OrderException(OrderException::ORDER_IS_NOT_EXISTS, OrderException::ORDER_IS_NOT_EXISTS_NO);
        }
        //获取商品标题
        $product =  AlibabaproductService::getInstance()->getOne($order['product_id']);
        if (empty($product))
            throw new AlibabaproductException(AlibabaproductException::ALIBABAPRODUCT_IS_NOT_EXISTS, AlibabaproductException::ALIBABAPRODUCT_IS_NOT_EXISTS_NO);
        $order_model = OrderModel::getInstance();
        $conn        = $order_model->getConn();
        $conn->beginTransaction();
        try {
            // 修改order表的订单状态为18(下单失败)
            $sql = "UPDATE `order` SET `stats` = '18' WHERE `sn` = '" . $order_sn . "'";
            Registry::get('db_log')->info("修改1688订单为下单失败的sql: " . $sql);
            $conn->executeQuery($sql);
            //退还总金额
            $amounts = $order['amount'];
            if ($order['fail_member_id']) {
                $failmember = MemberService::getInstance()->getOne($order['fail_member_id']);
                if (empty($failmember))
                    throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);

                // 下单失败新增一条归还余额的流水记录
                $sql = "INSERT INTO `turnover` (`type`, `member_id`, `stats`, `remark`, `currency`, `amount`, `remain`) " .
                    "VALUE ('4', '" . $order['fail_member_id'] . "', '1', '您在“{$product['title']}”未能成功参与拼单，归还余额。订单号：{$order_sn}', '" . $failmember['balance'] . "', '" . $amounts . "', '" . ($failmember['balance'] + $amounts) . "')";
                Registry::get('db_log')->info("下单失败，归还余额sql: " . $sql);
                $conn->executeQuery($sql);

                // 拼团失败归还余额
                $update_fail_member = "UPDATE `member` SET  `balance` = `balance` + " . $amounts . " WHERE `id` = '" . $failmember['id'] . "'";
                Registry::get('db_log')->info("下单失败,归还member的sql: " . $update_fail_member);
                $conn->executeQuery($update_fail_member);

                //推送消息给指定会员
                //消息推送
                $sql = "INSERT INTO `announce` (`type`, `member_id`, `title`, `content`, `is_push`, `created_at`) " .
                    "VALUE ('1', '" . $order['fail_member_id'] . "', '下单失败','您参与的“{$product['title']}”拼单交易失败，您所支付的金额已全额退回您的余额，请注意查收。','1','" . date('Y-m-d H:i:s', time()) . "')";
                Registry::get('db_log')->info("下单失败，消息推送sql: " . $sql);
                $conn->executeQuery($sql);

            }

            if ($order['member_id']) {
                $member = MemberService::getInstance()->getOne($order['member_id']);
                if (empty($member))
                    throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);

                // 下单失败新增一条归还余额的流水记录
                $sql = "INSERT INTO `turnover` (`type`, `member_id`, `stats`, `remark`, `currency`, `amount`, `remain`) " .
                    "VALUE ('4', '" . $order['member_id'] . "', '1', '您在“{$product['title']}”未能成功参与拼单，归还余额。订单号：{$order_sn}', '" . $member['balance'] . "', '" . $amounts . "', '" . ($member['balance'] + $amounts) . "')";
                Registry::get('db_log')->info("下单失败，归还余额sql: " . $sql);
                $conn->executeQuery($sql);

                // 拼团失败归还余额
                $update_fail_member = "UPDATE `member` SET  `balance` = `balance` + " . $amounts . " WHERE `id` = '" . $member['id'] . "'";
                Registry::get('db_log')->info("下单失败,归还member的sql: " . $update_fail_member);
                $conn->executeQuery($update_fail_member);

                //推送消息给指定会员
                //消息推送
                $sql = "INSERT INTO `announce` (`type`, `member_id`, `title`, `content`, `is_push`, `created_at`) " .
                    "VALUE ('1', '" . $order['member_id'] . "', '下单失败','您参与的“{$product['title']}”拼单交易失败，您所支付的金额已全额退回您的余额，请注意查收。','1','" . date('Y-m-d H:i:s', time()) . "')";
                Registry::get('db_log')->info("下单失败，消息推送sql: " . $sql);
                $conn->executeQuery($sql);

            }

            $conn->commit();
        } catch (ModelDriverException $e) {
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new OrderException(OrderException::ORDER_EDIT_FAILURE, OrderException::ORDER_EDIT_FAILURE_NO);
            throw $e;
        } catch (OrderException $e) {
            throw $e;
        } catch (MemberException $e) {
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        } catch (\Exception $e) {
            $conn->rollback();
            throw new OrderException(OrderException::ORDER_EDIT_FAILURE, OrderException::ORDER_EDIT_FAILURE_NO);
        }
    }

    /**
     * @param string $trade_order_sn
     * @param string $action
     * @param string $platform
     * @return bool
     * @throws MemberException
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws OrderException
     * @throws ServiceException
     * @throws TransformerException
     * @throws ylAlibabaException
     */
    static public function payOrRefund($trade_order_sn = '', $action = 'pay', $platform = 'alibaba') {
        if (! in_array($action, self::PAY_OR_REFUND_ACTION))
            throw new OrderException(BookingException::INVALID_BOOKING_STATS, BookingException::INVALID_BOOKING_STATS_NO);

        $redis = Registry::get('redis');
        try {
            $redis->ping();
        } catch (\Exception $e) {
            $redis->auth(Registry::get('config')['redis']['master']['auth']);
        }
        $key = $platform . '_delay_2_pay';
        $redis->select(9);

        if (0 === $len = $redis->lLen($key))
            throw new \Exception("没有等待下单的订单", 111);

        $get_data = false;
        $data = null;
        // 指定了第三方订单编号时,表示需要遍历list，从中取出与指定的第三方订单编号一致的订单来处理,则$loop为true
        // 反之 $loop为false
        $loop = !empty($trade_order_sn);
        if ($loop === false && $action === 'refund')
            throw new \Exception('退款订单的第三方订单号不能为空', 400);

        if ($loop === true) {
            $all_data = $redis->lRange($key, 0, -1);
            foreach ($all_data as $data) {
                if (null === $info = json_decode($data, true))
                    continue;
                else {
                    // 根据订单编号执行支付pay或refund操作时，需要将指定数据从list中删除
                    if ($action === 'pay' && $info['trade_order_sn'] === $trade_order_sn && time() >= $info['expire']) {
                        $redis->lRem($key, $data, 1);
                        $get_data = true;
                        break;
                    } else if ($action === 'refund' && $info['trade_order_sn'] === $trade_order_sn) {
                        $redis->lRem($key, $data, 1);
                        $get_data = true;
                        break;
//                        throw new \Exception("第三方订单编号:{$trade_order_sn}已从{$key}中删除", 111);
                    }
                }
            }
        } else {
            $data = $redis->lpop($key);
            if (null === $info = json_decode($data, true))
                throw new OrderException("无效数据类型", 400);
            // 还没到需要调用协议支付接口的时间点，就lpush回list
            if (time() < strtotime($data['expire'])) {
                $redis->lpush($key, $data);
            } else
                $get_data = true;
        }

        // 没有从list中读取到有用的数据
        if ($get_data === false)
            throw new \Exception("第三方订单编号:{$trade_order_sn}不存在于{$key}的队列中", 111);

        if (empty($trade_order_sn))
            throw new OrderException(OrderException::ORDER_TRADE_SN_EMPTY . '(trade_order_sn:' . $trade_order_sn . ')', OrderException::ORDER_ID_IS_EMPTY_NO);

        try {
            $order_info = Order::getOrderByTradeSn($trade_order_sn);
            // 校验订单是否存在
            if (empty($order_info))
                throw new OrderException();
        } catch (\Exception $e) {
            throw new OrderException(OrderException::ORDER_IS_NOT_EXISTS, OrderException::ORDER_IS_NOT_EXISTS_NO);
        }

        // pay时校验检查订单是否合法（stats = 1 and refund_stats = 0）
        if ($action === 'pay' && $order_info['stats'] == 1 && $order_info['refund_stats'] == 0)
            Alibaba::tradePayProtocolPay($trade_order_sn);
        else if ($action === 'refund' && $order_info['stats'] == 1 && $order_info['refund_stats'] == 1) {
            // 买家退款
            // 执行买家退款的代码
            $update_arr = [
                'refund_stats' => 3,
                'sn'           => $order_info['sn'],
            ];
            $order_update_res = Order::editOrder($update_arr);
            // 退款退运费扣除手续费
            $order_info['amount'] -= $order_info['service_fee'];
            //归还余额给用户
            self::handleRefund(1, $order_info);
        }
        // 订单状态不合法
        else
            throw new OrderException(OrderException::ORDER_STATUS_OPERATE, OrderException::ORDER_STATUS_OPERATE_NO);

        return true;
    }

    /**
     * 是否为新用户
     * @param $memberid
     * @param $first 第一次拼单成功
     */
    static public function newUser($memberid,$first=0){
        if($first){
            $count_sql = "SELECT count(`sn`) AS total FROM `order` WHERE member_id=". $memberid;
        }else{
            $count_sql = "SELECT count(`sn`) AS total FROM `order` WHERE member_id=". $memberid ." OR fail_member_id=". $memberid;
        }
        $count = OrderModel::getInstance()->query($count_sql);
        $newuser=  isset($count[0]['total'])?$count[0]['total']:0;
        if($first){
            return $newuser==1;
        }else{
            return $newuser==0;
        }
    }


    /**
     * 给拼团成功和拼团失败的用户发送推送消息
     * @param $sn
     */
    static public function couponPush($sn){
        $client = new client();
        try {
            $client->connect();
            $client->sendCouponRes($sn);
        } catch (Exception $e) {

        } finally {
            $client->close();
        }
    }

    /**
     * 第一次拼单，用户一定买不到商品
     * @param $booking
     * @param $sn_arr
     */
    static public function firstPinTuan($booking,$sn_arr){
        $order=[];
        $jqmem=-1;
        $k=-1;
        $system = SystemService::getInstance()->getOne(1);
        if($system['userwin']){
            $count  = count($sn_arr);
            //判断是否新用户
            $mem1= Order::newUser($booking[0]['member_id']);
            if($count==1){
                if($mem1){
                    //是新用户 1、新用户碰到机器人，新用户一定买不到商品,机器人买到；
                    $jqmem=1;
                    $k=1;
                }
            }
            if($count==2){
                $mem2= Order::newUser($booking[1]['member_id']);
                if($mem1){
                    if($mem2){
                        //3、新用户碰到新用户，两个新用户都买不到商品；
                        foreach ($sn_arr as $v){
                            $param['sn']=$v;
                            $data = Booking::getBookingList($param);
                            if(!empty($data)){
                                $order_data = Order::orderData($data['data'], 1, 1);
                                // 拼团商品需要在订单表创建订单
                                Order::createOrder($order_data);
                                Registry::get('order_log')->debug('订单数据：' . json_encode($order_data));
                                // 给拼团成功和拼团失败的用户发送推送消息
                                Order::couponPush($order_data['sn']);
                                $order_data['alibaba_order'] =[];
                                $order = Order::handleOrder($order_data);
                            }
                        }
                    }else{
                        //2、新用户碰到老用户，老用户买到商品，新用户则100%买不到商品；
                        //booking[0]为新用户 则booking[1]获取
                        $jqmem=0;
                        $k=1;
                    }
                }else{
                    if($mem2){
                        //2、新用户碰到老用户，老用户买到商品，新用户则100%买不到商品；
                        //booking[1]为新用户 则booking[0]获取
                        $jqmem=0;
                        $k=0;
                    }
                }

            }
        }
        return [$jqmem,$k,$order];
    }
}
